package com.gcxy.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gcxy.core.PageVO;
import com.gcxy.core.R;
import com.gcxy.dto.export.DownloadFileDTO;
import com.gcxy.dto.export.ExportRecordPageDTO;
import com.gcxy.entity.*;
import com.gcxy.enums.ResultCodeEnum;
import com.gcxy.mapper.ExportRecordMapper;
import com.gcxy.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gcxy.utils.*;
import com.gcxy.vo.record.ExportRecordVO;
import com.gcxy.vo.user.UserVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.gcxy.constant.StringConst.*;

/**
 * <p>
 * 导出周报记录表 服务实现类
 * </p>
 *
 * @author Huang先森
 * @since 2024-07-22
 */
@Slf4j
@Service
public class ExportRecordServiceImpl extends ServiceImpl<ExportRecordMapper, ExportRecord> implements ExportRecordService {

    @Autowired
    private SemesterService semesterService;

    @Autowired
    private AsyncThreadUtil asyncThreadUtil;

    @Autowired
    private GuidanceService guidanceService;

    @Autowired
    private WeeklyService weeklyService;

    @Autowired
    private UserService userService;

    @Autowired
    private AgencyService agencyService;

    @Autowired
    private ProjectService projectService;

    /**
     * 生成文件
     *
     * @param dto
     * @return
     */
    @Override
    public R<?> createFile(DownloadFileDTO dto) {
        //学期信息
        Semester semester = semesterService.getById(dto.getSemesterId());
        if (ObjectUtils.isEmpty(semester)) {
            return R.Failed("未找到当前学期信息");
        }
        String exportWeekNum = "第" + dto.getBeginWeekNum() + "周到第" + dto.getEndWeekNum() + "周";
        String fileName = semester.getName() + "-" + exportWeekNum + "-" + System.currentTimeMillis() + ".zip";
        String targetPath = DEFAULT_ZIP_PATH + fileName;
        ExportRecord exportRecord = new ExportRecord();
        exportRecord.setExportTime(LocalDateTime.now());
        exportRecord.setExportStatus(0);
        exportRecord.setUrl(targetPath);
        exportRecord.setFileName(fileName);
        exportRecord.setSemesterId(semester.getId());
        exportRecord.setSemesterName(semester.getName());
        exportRecord.setExportWeekNum(exportWeekNum);
        exportRecord.setAgencyId(dto.getAgencyId());
        if (save(exportRecord)) {
            asyncThreadUtil.asyncCreateFile(dto, targetPath);
            return R.Success();
        }
        return R.Failed("新增导出周报记录信息错误");
    }

    /**
     * 生成文件
     *
     * @param dto
     * @param targetPath
     */
    @Override
    public void createFile(DownloadFileDTO dto, String targetPath) {
        //生成周指导记录word文件
        R<?> guidanceFile = guidanceService.createGuidanceFile(dto);
        if (guidanceFile.failed()) {
            updateStatus(targetPath, 2);
            log.error("生成周指导记录word文件失败：{}", guidanceFile.getMsg());
        }
        //生成学生周打分excel文件
        R<?> weeklyEvaluateR = weeklyService.createEvaluateFile(dto);
        if (weeklyEvaluateR.failed()) {
            updateStatus(targetPath, 2);
            log.error("生成学生周打分excel文件失败：{}", weeklyEvaluateR.getMsg());
        }
        //生成周报word文件
        R<?> weeklyFileR = weeklyService.createWeeklyFile(dto);
        if (weeklyFileR.failed()) {
            updateStatus(targetPath, 2);
            log.error("生成周报word文件失败：{}", weeklyFileR.getMsg());
        }
        //生成学生项目清单excel文件
        R<?> projectStudentFileR = projectService.createProjectStudentListFile(dto);
        if (projectStudentFileR.failed()) {
            updateStatus(targetPath, 2);
            log.error("生成学生项目清单excel文件失败：{}", projectStudentFileR.getMsg());
        }
        //压缩文件
        try {
            ZipUtil.zipFolder(DEFAULT_FILE_PATH, targetPath);
            log.info("文件压缩成功");
        } catch (IOException e) {
            updateStatus(targetPath, 2);
            log.error("异步生成文件失败：{}", e.getMessage());
        }
        updateStatus(targetPath, 1);
        log.error("异步生成文件成功");
    }

    /**
     * 通过id下载文件
     *
     * @param id
     * @param response
     * @return
     */
    @Override
    public R<?> download(Integer id, HttpServletResponse response) {
        ExportRecord exportRecord = getById(id);
        if (exportRecord == null) {
            return R.Failed(ResultCodeEnum.NO_FILE.getCode(), ResultCodeEnum.NO_FILE.getMessage());
        }
        try {
            InputStream fis = new BufferedInputStream(new FileInputStream(exportRecord.getUrl()));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();
            // 设置response的Header
            response.setContentType("multipart/form-data");
            response.setHeader("Content-Disposition", "attachment;filename="
                    + java.net.URLEncoder.encode(exportRecord.getFileName(), "UTF-8"));
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        } catch (Exception e) {
            log.error("压缩包下载失败：{}", e.getMessage());
            return R.Failed("压缩包下载失败");
        }
        return R.Success();
    }

    /**
     * 分页查询导出记录
     *
     * @param exportRecordPageDto
     * @return
     */
    @Override
    public R<PageVO<ExportRecordVO>>  getExportRecordByPage(ExportRecordPageDTO exportRecordPageDto) {
        UserVO userInfo = userService.getUserInfo();

        Page<ExportRecord> page = new Page<>();
        page.setSize(exportRecordPageDto.getPageSize());
        page.setCurrent(exportRecordPageDto.getPageNo());

        LambdaQueryWrapper<ExportRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(exportRecordPageDto.getExportStatus() != null, ExportRecord::getExportStatus, exportRecordPageDto.getExportStatus())
//                .eq(exportRecordPageDto.getAgencyId() != null, ExportRecord::getAgencyId, exportRecordPageDto.getAgencyId())
                .eq(exportRecordPageDto.getSemesterId() != null, ExportRecord::getSemesterId, exportRecordPageDto.getSemesterId())
                .eq(ExportRecord::getUpdater, userInfo.getUsername())
                .orderByDesc(ExportRecord::getCreateTime);
        Page<ExportRecord> exportPage = page(page, lambdaQueryWrapper);
        PageVO<ExportRecordVO> exportRecordPageVO = new PageVO<>();
        BeanUtils.copyProperties(exportPage, exportRecordPageVO);
        List<ExportRecordVO> exportRecordVOList = exportPage.getRecords().stream().map(exportRecord -> {
            ExportRecordVO exportRecordVO = BeanCopyUtil.copy(exportRecord, ExportRecordVO.class);
            exportRecordVO.setExportTime(exportRecord.getExportTime().toString());
            exportRecordVO.setAgencyName(agencyService.getById(exportRecord.getAgencyId()).getName());
            return exportRecordVO;
        }).collect(Collectors.toList());
        exportRecordPageVO.setRecords(exportRecordVOList);
        return R.Success(exportRecordPageVO);
    }

    /**
     * 修改导出记录状态
     *
     * @param url
     * @param status
     */
    public void updateStatus(String url, Integer status) {
        LambdaUpdateWrapper<ExportRecord> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(ExportRecord::getExportStatus, status)
                .eq(ExportRecord::getUrl, url);
        update(updateWrapper);
    }

}
